import datetime
import os.path
from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile, Form, Path, Body, Request
from typing import List
from tempfile import NamedTemporaryFile
from model.User import UserModel
from pathlib import Path
from router.route_log import LogRoute
from common.response import ApiResponse, CustomApiResponse, response_code, responseCode
from pydantic import BaseModel
from common.custom_log import my_logger
from common.setting import settings
from utils.handle_image import imageClip, get_root_path, makeGetFileUrl

router = APIRouter(prefix='/upload',route_class=LogRoute)

credentials_exception = HTTPException(
    status_code=status.HTTP_200_OK,
    detail=ApiResponse().set_api_dict(),
)


# 上传附件 携带参数
class uploadForm(BaseModel):
    type: str | None = 'image'
    maxLength: int | None = None
    allow: List[str] | None = None


# 图片格式
image_type = ['image/png', 'image/jpeg', 'image/gif']

# excel格式
file_type = [
    'application/vnd.ms-excel',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'application/vnd.ms-excel',
    'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
    'application/vnd.ms-powerpoint',
    'application/vnd.ms-access',
    'text/plain',
    'text/html'
]


# 保存至指定地址
async def saveFile(file: UploadFile = None, savePath: str = 'upload'):
    content = await file.read()
    firsttime = datetime.datetime.today()
    nowtime = datetime.datetime.date(firsttime)
    save_dir_path = savePath
    # 判断static下的upload是否存在不存在则建立
    uploadpath = os.path.join(settings.staticPath, save_dir_path)
    if not os.path.exists(uploadpath):
        os.mkdir(uploadpath)
    # 建立日期文件夹存储文件
    save_dir = os.path.join(settings.staticPath, save_dir_path, str(nowtime))
    if not os.path.exists(save_dir):
        os.mkdir(save_dir)
    try:
        suffix = Path(file.filename).suffix
        # 这种方式就是直接生成新文件
        # with open(os.path.join(save_dir,file.filename),'wb') as f:
        #     f.write(content)

        # 这种是直接使用临时文件名生成文件 时候会删除临时文件
        with NamedTemporaryFile(delete=False, suffix=suffix,
                                dir=save_dir) as tmp:
            tmp.write(content)
            tmp_file_name = Path(tmp.name).name
        my_logger.info(f"上传图片 {tmp_file_name} 成功.")
    except Exception:
        credentials_exception.detail = ApiResponse(code=response_code.get('Error'), message='上传失败').set_api_dict()
        raise credentials_exception
    finally:
        file.file.close()
    return os.path.join(save_dir, tmp_file_name)


# 验证是否为空文件
def check_file_empty(uploadfiles: List[UploadFile] = File(...), filetype: str = None):
    filesizes = [file.size for file in uploadfiles]
    filesType = [file.content_type for file in uploadfiles]
    for file in uploadfiles:
        if filetype == 'image':
            try:
                image_type.index(file.content_type)
            except ValueError:
                credentials_exception.detail = ApiResponse(message="请确认文件格式",
                                                           code=response_code.get('Error')).set_api_dict()
                raise credentials_exception
        else:
            try:
                for single_file in filesType:
                    file_type.index(single_file)
            except ValueError:
                credentials_exception.detail = ApiResponse(message="请确认文件格式",
                                                           code=response_code.get('Error')).set_api_dict()
                raise credentials_exception
    return sum(filesizes)


# 验证文件
async def validate_file(uploadfile: UploadFile):
    fileSize = uploadfile.size
    fileName = uploadfile.filename
    fileType = uploadfile.content_type
    savePath = await saveFile(uploadfile)
    return {
        'fileSize': fileSize,
        'fileName': fileName,
        'fileType': fileType,
        'savePath': savePath
    }


# 如果需要设置单文件上传则files: UploadFile = File(...) 或者file: bytes = File(...,content_type=image_type) 不得超过max_length 字节
@router.post("/multi", summary="上传附件", description='多附件上传')
async def multiple_update(current_user=Depends(UserModel.get_current_user),
                          files: List[UploadFile] = File(..., max_length=100000),
                          uploadType=Form(default='image')) -> dict:
    filesizesTotal = check_file_empty(files, uploadType)
    if filesizesTotal <= 0:
        credentials_exception.detail = ApiResponse(message="附件列表不得为空",
                                                   code=response_code.get('Error')).set_api_dict()
        raise credentials_exception
    my_logger.info(f"用户 {current_user.get('username')} 正在上传附件...")
    try:
        backFilelist = []
        for file in files:
            savepath = await validate_file(uploadfile=file)
            backFilelist.append(savepath)
    except HTTPException as e:
        credentials_exception.detail = e.detail
        raise credentials_exception
    return ApiResponse(data=backFilelist).set_api_dict()


# 单文件上传
@router.post("/sigle", summary="上传附件", description='单附件上传')
async def single_update(request: Request, file_type: str = Form(default='image'),
                        current_user=Depends(UserModel.get_current_user),
                        file: UploadFile = File(...)) -> dict:
    filesizesTotal = check_file_empty([file], filetype=file_type)
    if filesizesTotal <= 0:
        credentials_exception.detail = ApiResponse(message="附件列表不得为空",
                                                   code=response_code.get('Error')).set_api_dict()
        raise credentials_exception
    my_logger.info(f"用户 {current_user.get('username')} 正在上传附件...")
    try:
        savepath = await validate_file(uploadfile=file)
        my_logger.info(f'已上传文件：{savepath.get("savePath")}')
        back = {
            # 'url': f'{request.base_url}{savepath.get("savePath")}',
            'url': makeGetFileUrl(request, query={'width': 300}, filepath='\\' + savepath.get("savePath")),
            'size': savepath.get('fileSize'),
            'savepath': savepath.get("savePath"),
            'name': savepath.get('fileName')
        }
    except HTTPException as e:
        credentials_exception.detail = e.detail
        raise credentials_exception
    return ApiResponse(data=back).set_api_dict()


@router.get("/viewfile", summary="预览图片", description='预览图片')
async def getView(filepath, outputMode: str = 'jpeg', width: int = None, height: int = None):
    rootpath = get_root_path() + filepath
    return await imageClip(filepath=rootpath, outputMode=outputMode, width=width, height=height)
